import { Component, OnDestroy, OnInit, ViewChild, EventEmitter, AfterViewInit } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { merge, of as observableOf } from 'rxjs';
import { DateAdapter } from '@angular/material/core';
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
import { Router } from '@angular/router';
import { MatDialog } from '@angular/material';
import { RestService } from '../services/rest.service';
import { TranslateService } from '@ngx-translate/core';
import { DialogTypes } from '../models/wdl-types';
import { ExportAlarmDialogComponent } from './export-alarm-dialog/export-alarm-dialog.component';
import { environment } from 'environments/environment';

import * as _ from 'lodash';

@Component({
  templateUrl: './alarm.component.html',
  styleUrls: ['./alarm.component.css'],
})
export class AlarmComponent implements OnInit, OnDestroy, AfterViewInit {
  refreshInterval = environment.interval;
  refreshTask: any;
  enableRefresh = true;

  url = 'data/alarm';
  institution: any;
  user: any;
  displayedColumns: string[] = ['number', 'raisedTime', 'type', 'ackedTime', 'personName', 'deviceId', 'actions'];
  dataSource = [];
  searchText = '';
  isLoadingResults = true;

  resultsLength = 0;
  pageSize = 25;

  search: EventEmitter<any> = new EventEmitter();

  fromTime;
  toTime;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor(public dialog: MatDialog,
              private router: Router,
              private adapter: DateAdapter<any>,
              private translate: TranslateService,
              private rest: RestService) {
    this.institution = this.rest.getInstitution();
    if (!this.institution.id) {
      console.error('Instituion is invalid: ' + this.institution.id);
    }

    this.user = this.rest.getUser();
    if (!this.isUserQualified()) {
      this.displayedColumns = ['raisedTime', 'type', 'ackedTime', 'personName', 'deviceId'];
    }

    switch (this.translate.currentLang) {
    case 'en':
      this.adapter.setLocale('en');
      break;
    case 'tw':
      this.adapter.setLocale('zh-TW');
      break;
    case 'zh':
    default:
      this.adapter.setLocale('zh-CN');
      break;
    }
  }

  isUserQualified() {
    return this.user.role !== 'director' && this.user.role !== 'doctor';
  }

  fromChange(event) {
    if (event.value) {
      this.fromTime = event.value.getTime();
    } else {
      this.fromTime = null;
    }

    this.refreshSearch();
  }

  toChange(event) {
    if (event.value) {
      this.toTime = new Date(event.value).setHours(23, 59, 59, 999);
    } else {
      this.toTime = null;
    }

    this.refreshSearch();
  }

  refreshSearch() {
    this.paginator.pageIndex = 0;
    this.search.emit(this.searchText);
  }

  setFilterPerson(alarm) {
    if (alarm['personName']) {
      this.searchText = alarm['personName'];
      this.refreshSearch();
    }
  }

  stop() {
    this.enableRefresh = false;
    if (this.refreshTask) {
      clearTimeout(this.refreshTask);
    }
  }

  resume() {
    this.enableRefresh = true;
    this.scheduleNext();
  }

  export() {
    // export all of the alarms
    const params = {};
    const dataUrl = this.buildRestRequestUrl(params);
    this.dialog.open(ExportAlarmDialogComponent, {
      disableClose: true,
      autoFocus: false,
      width: '450px',
      data: {
        url: dataUrl,
        params: params
      }
    });
  }

  getHideAlarmType(alarm) {
    return 'hide' + _.capitalize(alarm.type) + 'Alarm';
  }

  getAlarmFlag(alarm) {
    return alarm.type.toLowerCase() + 'AlarmFlag';
  }

  ack(alarm) {
    this.rest.postWithParams('data/ackAlarm', {alarmId: alarm.id}, {}).subscribe(result => {
      this.refreshSearch();
    }, message => {
      this.rest.showHttpError(this.translate.get('error')['value'], message);
    });
  }

  unack(alarm) {
    this.rest.patch(this.url + '/' + alarm.id, {ackedTime: 0}).subscribe(result => {
      const data = {};
      data[this.getHideAlarmType(alarm)] = false;
      if (alarm.type === 'MOVE') {
        data['moveAlarmFlag'] = true;
        data['moveAlarmAckTime'] = 0;
      }
      this.rest.patch('data/person/' + alarm.personId, data).subscribe(() => {
      });
      this.refreshSearch();
    }, message => {
      this.rest.showHttpError(this.translate.get('error')['value'], message);
    });
  }

  remove(alarm) {
    const title = this.translate.get('deleteConfirmation')['value'];
    const message = this.translate.get('deleteAlarmMessage', {type: alarm.type})['value'];

    this.rest.openGenDialog(DialogTypes.CONFIRMATION, title, message, () => {
      this.rest.delete(this.url + '/' + alarm.id).subscribe(result => {
        const data = {};
        data[this.getAlarmFlag(alarm)] = false;
        data[this.getHideAlarmType(alarm)] = false;
        this.rest.patch('data/person/' + alarm.personId, data).subscribe(() => {});
        this.refreshSearch();
      }, error => {
        this.rest.showHttpError(this.translate.get('error')['value'], error);
      });
    });
  }

  buildRestRequest() {
    const params = {
      institutionId: this.institution.id,
      page: this.paginator.pageIndex ? this.paginator.pageIndex : 0,
      size: this.paginator.pageSize ? this.paginator.pageSize : this.pageSize
    };

    if (this.sort.active && this.sort.direction) {
      params['sort'] = this.sort.active + ',' + this.sort.direction
    }

    if (!this.fromTime && !this.toTime) {
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.rest.getWithParams(this.url + '/search/name', params);
      } else {
        return this.rest.getWithParams(this.url + '/search/all', params);
      }
    } else if (this.fromTime && !this.toTime) {
      params['startTime'] = this.fromTime;
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.rest.getWithParams(this.url + '/search/nameStartTime', params);
      } else {
        return this.rest.getWithParams(this.url + '/search/allStartTime', params);
      }
    } else if (!this.fromTime && this.toTime) {
      params['endTime'] = this.toTime;
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.rest.getWithParams(this.url + '/search/nameEndTime', params);
      } else {
        return this.rest.getWithParams(this.url + '/search/allEndTime', params);
      }
    } else {
      params['startTime'] = this.fromTime;
      params['endTime'] = this.toTime;
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.rest.getWithParams(this.url + '/search/nameStartTimeEndTime', params);
      } else {
        return this.rest.getWithParams(this.url + '/search/allStartTimeEndTime', params);
      }
    }
  }

  buildRestRequestUrl(params: any) {
    params['institutionId'] = this.institution.id;
    params['page'] = 0;
    params['size'] = 1000;

    if (this.sort.active && this.sort.direction) {
      params['sort'] = this.sort.active + ',' + this.sort.direction
    }

    if (!this.fromTime && !this.toTime) {
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.url + '/search/name';
      } else {
        return this.url + '/search/all';
      }
    } else if (this.fromTime && !this.toTime) {
      params['startTime'] = this.fromTime;
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.url + '/search/nameStartTime';
      } else {
        return this.url + '/search/allStartTime';
      }
    } else if (!this.fromTime && this.toTime) {
      params['endTime'] = this.toTime;
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.url + '/search/nameEndTime';
      } else {
        return this.url + '/search/allEndTime';
      }
    } else {
      params['startTime'] = this.fromTime;
      params['endTime'] = this.toTime;
      if (this.searchText) {
        params['personName'] = this.searchText;
        return this.url + '/search/nameStartTimeEndTime';
      } else {
        return this.url + '/search/allStartTimeEndTime';
      }
    }
  }

  ngAfterViewInit() {
    // If the user changes the sort order, reset back to the first page.
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page, this.search)
    .pipe(
      startWith({}),
      switchMap(() => {
        return this.buildRestRequest();
      }),
      map(data => {
        this.isLoadingResults = false;
        this.resultsLength = data['page']['totalElements'];

        let number = this.paginator.pageIndex * this.paginator.pageSize;
        const alarms = data['_embedded']['alarms'];
        alarms.forEach(alarm => {
          alarm['number'] = ++number;
        });

        this.scheduleNext();
        return alarms;
      }),
      catchError(() => {
        this.isLoadingResults = false;
        this.scheduleNext();
        return observableOf([]);
      })
    ).subscribe(data => this.dataSource = data);
  }

  scheduleNext() {
    if (this.rest.getCurrentApp() !== 'alarm' || !this.enableRefresh) {
      return;
    }

    if (this.refreshTask) {
      clearTimeout(this.refreshTask);
    }

    this.refreshTask = setTimeout(() => {
      if (this.rest.getCurrentApp() !== 'alarm' || !this.enableRefresh) {
        return;
      }

      this.search.emit(this.searchText);
    }, this.refreshInterval);
  }

  ngOnInit() {
  }

  ngOnDestroy() {
    if (this.refreshTask) {
      clearTimeout(this.refreshTask);
    }
  }
}
